package models

import (
	"NewEdu/utils"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"

	"github.com/beego/beego/v2/client/orm"
	"github.com/redis/go-redis/v9"
)

type TDepart struct {
	Id       int        `orm:"column(id);auto" description:"主键"`
	Label    string     `orm:"column(label);size(45);null" description:"名称"`
	Desc     string     `orm:"column(desc);size(145);null" description:"描述"`
	ParentId int        `orm:"column(parent_id);null" description:"父部门id,如果是0 则为学院,1为专业,2为班级,3为群组"`
	Children []*TDepart `json:"Children" orm:"-"`
}

func (t *TDepart) TableName() string {
	return "t_depart"
}

func init() {
	orm.RegisterModel(new(TDepart))
}

// AddTDepart insert a new TDepart into database and returns
// last inserted Id on success.
func AddTDepart(m *TDepart) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetTDepartById retrieves TDepart by Id. Returns error if
// Id doesn't exist
func GetTDepartById(id int) (v *TDepart, err error) {
	ctx := context.Background()
	var itemJson []byte
	itemJson, err = utils.RedisClient.Get(ctx, fmt.Sprintf("depart:%d", id)).Bytes()
	if err == nil {
		v = new(TDepart)
		err = json.Unmarshal(itemJson, v)
		if err == nil {
			return
		}
		return
	}
	o := orm.NewOrm()
	v = &TDepart{Id: id}
	if err = o.Read(v); err == nil {
		return v, nil
	}
	return nil, err
}

// GetAllTDepart retrieves all TDepart matches certain condition. Returns empty list if
// no records exist
func GetAllTDepart(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(TDepart))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		if strings.Contains(k, "isnull") {
			qs = qs.Filter(k, (v == "true" || v == "1"))
		} else {
			qs = qs.Filter(k, v)
		}
	}
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []TDepart
	qs = qs.OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateTDepart updates TDepart by Id and returns error if
// the record to be updated doesn't exist
func UpdateTDepartById(m *TDepart) (err error) {
	o := orm.NewOrm()
	v := TDepart{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteTDepart deletes TDepart by Id and returns error if
// the record to be deleted doesn't exist
func DeleteTDepart(id int) (err error) {
	o := orm.NewOrm()
	v := TDepart{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Delete(&TDepart{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)
		}
	}
	return
}
func LoadDepart2Redis() error {
	o := orm.NewOrm()
	qs := o.QueryTable(new(TDepart))
	var allDepart []TDepart
	if _, err := qs.All(&allDepart); err != nil {
		return err
	}
	fmt.Println("载入 depart 到 redis 中数为:", len(allDepart))
	ctx := context.Background()
	var err error
	var itemJson []byte
	for _, depart := range allDepart {
		itemJson, err = json.Marshal(depart)
		if err != nil {
			return err
		}
		cmd := utils.RedisClient.Set(ctx, fmt.Sprintf("depart:%d", depart.Id), itemJson, 0)
		if cmd.Err() != nil {
			fmt.Println("depart 写入到 redis 出错:", cmd.Err())
			return cmd.Err()
		}
	}
	return nil
}

func LoadAllDepart() ([]*TDepart, error) {
	ctx := context.Background()
	keys, err := utils.RedisClient.Keys(ctx, "depart:*").Result()
	if err != nil {
		return nil, err
	}
	var departList []*TDepart
	for _, key := range keys {
		val, err := utils.RedisClient.Get(ctx, key).Bytes()
		if err == redis.Nil {
			fmt.Printf("Key %s does not exist\n", key)
			continue
		} else if err != nil {
			return nil, err
		}
		var depart TDepart
		if err := json.Unmarshal(val, &depart); err != nil {
			return nil, err
		}
		departList = append(departList, &depart)
	}
	return departList, nil
}

// buildTree 函数使用递归算法构建树形结构，返回根节点切片
func BuildTree(nodes []*TDepart) []*TDepart {
	nodeMap := make(map[int]*TDepart)
	var roots []*TDepart

	// 首先将所有节点存储到 nodeMap 中
	for _, node := range nodes {
		nodeMap[node.Id] = node
		node.Children = []*TDepart{}
	}

	// 构建树结构
	for _, node := range nodes {
		if node.ParentId == 0 {
			roots = append(roots, node)
		} else {
			parent, exists := nodeMap[node.ParentId]
			if exists {
				parent.Children = append(parent.Children, node)
			}
		}
	}

	return roots
}
